home *** CD-ROM | disk | FTP | other *** search
- /*
- prb.c - Packetized Ring Buffer demonstration
-
- (c) Copyright 1989, 1990 Martin J. Stitt
- */
-
- #include <alloc.h>
- #include <string.h>
- #include <stdlib.h>
-
- typedef unsigned char byte;
- typedef unsigned int word;
-
- typedef struct {
- word prb_totbytes; /* define the ring buffer's size */
- byte *prb_base; /* ptr to base of buffer */
- byte *prb_head; /* head ptr - from which data is read */
- byte *prb_tail; /* tail ptr - at which data is written */
- word prb_free; /* amount of free space in the buffer */
- word prb_eobofs; /* offset of byte just past the eob */
- byte prb_packets; /* number of records in the buffer */
- byte prb_use_rectype; /* indicates use of two byte headers */
- word prb_overflow; /* indicates when a record is too large */
- byte prb_max_dsize; /* maximum size for record's data */
- } prb_type;
-
- /*- prb_init -----------------------------------------------------------
- entry parms: ptr to a partially initialized prb structure
- prb_base must point to an allocated buffer
- prb_totbytes must be its size
- prb_use_rectype must be assigned
- exit parms: function return value != 0 when the last buffer
- offset is 0xFFFF
- notes: call before writing and reading. can recall later to flush the
- ring buffer. can ignore return value on sucessive calls.
- ------------------------------------------------------------------------*/
- word prb_init(prb_type *b) {
-
- b->prb_head = b->prb_base; /* initialize the pointers */
- b->prb_tail = b->prb_base; /* to flush the buffer */
- b->prb_free = b->prb_totbytes;
- b->prb_packets = 0;
- b->prb_max_dsize = 255-1; /* -1 for the header byte */
- if(b->prb_use_rectype) b->prb_max_dsize--; /* if using 2 byte header */
- b->prb_overflow = 0;
- b->prb_eobofs = (word) b->prb_base + b->prb_totbytes;
- return((b->prb_eobofs == 0) ? 1 : 0);
- }
-
- /*- prb_write_data ---------------------------------------------------------
- entry parms: ptr to buffer structure
- ptr to caller's data, size of caller's data
- record type code (ignored if prb_use_rectype == 0)
- exit parms: function return value != 0 if overflow
- ------------------------------------------------------------------------*/
- word prb_write_data(prb_type *b, void *idata, byte dsize, byte rectype) {
-
- byte csize; /* data bytes to xfer */
- byte psize; /* total packet size */
- word block1; /* bytes before wrap of tail */
- byte need_wrap; /* flags need for a 2 part xfer */
- word adjust_head; /* bytes to advance the head ptr */
- word head2end; /* bytes before wrap of head */
-
- if(dsize == 0) return(1); /* anything to insert? */
- if(dsize > b->prb_max_dsize) return(1); /* don't allow oversized data */
- psize = dsize+1; /* +1 for the pkt size header byte */
- if(b->prb_use_rectype) { /* if using a record type */
- psize++; /* account for header byte */
- }
- if(psize > b->prb_totbytes) { /* if record too large for buffer */
- if(psize < b->prb_overflow) { /* record overflow unless another */
- b->prb_overflow = psize; /* larger recorded */
- }
- return(1); /* indicate a problem */
- }
- while(psize > b->prb_free) { /* while not enough free room */
- b->prb_free += *b->prb_head; /* adjust free to show deletion */
- b->prb_packets--; /* adjust accounting of pkts */
- adjust_head = *b->prb_head; /* fetch size of pkt to be deleted */
- head2end = b->prb_eobofs - (word) b->prb_head; /* calc bytes till wrap */
- if(adjust_head > head2end) { /* will deletion involve a wrap? */
- adjust_head -= head2end; /* calc bytes in second portion */
- b->prb_head = b->prb_base; /* wrap around */
- }
- b->prb_head += adjust_head; /* advance the head pointer */
- if((word) b->prb_head == b->prb_eobofs) { /* if pkt deleted just fit */
- b->prb_head = b->prb_base; /* need to wrap */
- }
- }
- block1 = b->prb_eobofs - (word) b->prb_tail; /* calc size of 1st block */
- b->prb_packets++; /* update accounting of pkts */
- b->prb_free -= psize; /* update accounting of free space */
- csize = psize-1; /* sub 1 for pkt size header byte */
- *(b->prb_tail++) = psize; /* write header byte, advance tail */
- need_wrap = 0; /* initialize flag */
- if(psize > block1) { /* if won't all fit in 1st block */
- need_wrap = 1; /* write remainder in 2nd block */
- csize = block1-1; /* -1 for header already written */
- if(csize == 0) { /* if block1 only had 1 byte */
- b->prb_tail = b->prb_base; /* do the wrap now */
- need_wrap = 0; /* don't need to wrap later */
- csize = psize-1; /* -1 for header already written */
- }
- }
- if(b->prb_use_rectype) { /* if type code to be inserted */
- *(b->prb_tail++) = rectype; /* insert it now and advance tail */
- csize--; /* account for type code */
- if(csize == 0) { /* if block1 only had 2 bytes */
- b->prb_tail = b->prb_base; /* do the wrap now */
- need_wrap = 0; /* don't need to wrap later */
- csize = psize-2; /* account for 2 bytes in header */
- }
- }
- memmove(b->prb_tail,idata,csize); /* insert csize bytes into buffer */
- b->prb_tail += csize; /* advance tail past new data */
- if(need_wrap) { /* if more data left to insert */
- b->prb_tail = b->prb_base; /* wrap the tail back around */
- (byte) idata += csize; /* advance the caller's pointer */
- memmove(b->prb_tail,idata,(psize-block1)); /* insert the remaining data */
- b->prb_tail += (psize-block1);
- }
- if(b->prb_eobofs == (word) b->prb_tail) { /* if blk went just up to end */
- b->prb_tail = b->prb_base; /* need to wrap tail back around */
- }
- return(0); /* indicate success */
- }
-
- /*- prb_read_rectype ---------------------------------------------------
- entry parms: ptr to buffer structure
- address of byte to receive rectype
- exit parms: function return value is data size
- 0 means buffer is empty
-
- notes: presumes all ring buffer records contain a rectype byte in
- their header. if the buffer is empty, the rectype value returned
- will be garbage.
- ------------------------------------------------------------------------*/
- byte prb_read_rectype(prb_type *b, byte *rectype) {
-
- byte *tptr; /* local scratch pointer */
-
- if(b->prb_packets == 0) return(0); /* anything in buffer? */
- tptr = b->prb_head + 1; /* point to the record type code */
- if(b->prb_eobofs == (word) tptr) { /* need to wrap to read */
- tptr = b->prb_base; /* the 2nd byte? */
- }
- *rectype = *tptr; /* transfer rectype to caller */
- return(*b->prb_head-2); /* return the record size */
- }
-
- /*- prb_read_data -----------------------------------------------------------
- entry parms: ptr to buffer structure
- address of buffer to receive record contents
- exit parms: function return value is data size
- 0 means buffer is empty
-
- notes: presumes caller has referenced any recorded rectype and has
- supplied a pointer to a large enough buffer. *prb_head can be
- referenced to verify the size requirement.
- ------------------------------------------------------------------------*/
- byte prb_read_data(prb_type *b, void *dest) {
-
- byte dsize; /* data bytes in packet */
- byte csize; /* bytes to transfer */
- byte rsize; /* bytes left when need 2 xfers */
- word block1; /* bytes before wrap */
-
- if(b->prb_packets == 0) return(0); /* make sure buffer has data */
- b->prb_free += *b->prb_head; /* adjust free to show deletion */
- b->prb_packets--; /* adjust accounting of packets */
- rsize = 0; /* init remainder var */
- csize = *b->prb_head; /* fetch the record size */
- dsize = csize - 1; /* record the data size */
- block1 = b->prb_eobofs - (word) b->prb_head; /* calc size of 1st block */
- if(csize > block1) { /* if a wrap will be required */
- rsize = csize - block1; /* calculate the remainder */
- csize = block1; /* adjust csize to do 1st blk only */
- }
- csize--; /* account for record size header */
- b->prb_head++; /* step past record size header */
- if(csize == 0) { /* if done with 1st block already */
- b->prb_head = b->prb_base; /* wrap the head back around */
- csize = rsize; /* start accounting with remainder */
- rsize = 0; /* signal that wrap has been done */
- }
- if(b->prb_use_rectype) { /* if using a two byte header */
- b->prb_head++; /* step past the record type */
- csize--; /* adjust accounting */
- dsize--; /* adjust accounting */
- if(csize == 0) { /* if done with 1st block */
- b->prb_head = b->prb_base; /* wrap the head back around */
- csize = rsize; /* start accounting with remainder */
- rsize = 0; /* signal that wrap has been done */
- }
- }
- memmove(dest,b->prb_head,csize); /* tranfer 1st block to caller */
- b->prb_head += csize; /* advance head past copied data */
- if(rsize != 0) { /* if any remainder in a 2nd block */
- b->prb_head = b->prb_base; /* wrap the head back around */
- (byte) dest += csize; /* advance dest past copied data */
- memmove(dest,b->prb_head,rsize); /* transfer the 2nd block */
- b->prb_head += rsize; /* advance head past copied data */
- }
- if(b->prb_eobofs == (word) b->prb_head) { /* if blk went just up to end */
- b->prb_head = b->prb_base; /* need to wrap head back around */
- }
- return(dsize); /* report the data size */
- }
-
- /*------------------------------- main ------------------------------*/
-
- main() {
-
- prb_type sample; /* record to hold buffer data */
- byte workbuf[256]; /* general purpose buffer */
- byte rlen; /* size of data in read records */
- word x,y; /* general purpose words */
- byte rectype; /* type of record being read */
-
- sample.prb_totbytes = 100;
- sample.prb_use_rectype = 0;
- if((sample.prb_base = malloc(sample.prb_totbytes)) == NULL) {
- printf("\nInsufficient memory\n");
- exit(1);
- }
- if(prb_init(&sample) != 0) { /* make sure position is ok */
- printf("\nBuffer ends at FFFF\n");
- exit(1);
- }
-
- /*
- write some strings into the buffer. since all packets will hold
- the same type of data, the rectype field is not used.
- */
-
- strcpy(workbuf,"1234567890123456789012345678901234567890123456789");
- prb_write_data(&sample,workbuf,strlen(workbuf),0);
- strcpy(workbuf,"123456789012345678901234567890123456789012345678");
- prb_write_data(&sample,workbuf,strlen(workbuf),0);
- strcpy(workbuf,"this will cause a wrap");
- prb_write_data(&sample,workbuf,strlen(workbuf),0);
-
- /* dump the buffer's contents */
-
- printf("\n\n");
- while((rlen = prb_read_data(&sample,workbuf)) != 0) {
- *(workbuf+rlen) = 0; /* add string terminator */
- puts(workbuf);
- }
-
- /*
- write some differing types of records. text strings will be
- identified by a rectype of 0 and integers with a rectype of 1.
- */
-
- sample.prb_use_rectype = 1;
- prb_init(&sample); /* flush buffer and activate record types */
- strcpy(workbuf,"text is rectype 0");
- prb_write_data(&sample,workbuf,strlen(workbuf),0);
- x = 0x1234;
- prb_write_data(&sample,&x,2,1);
- strcpy(workbuf,"more text");
- prb_write_data(&sample,workbuf,strlen(workbuf),0);
- prb_write_data(&sample,"can send a literal string",25,0);
- prb_write_data(&sample,"but must count its chars",24,0);
- prb_write_data(&sample,"this will cause a wrap",22,0);
-
- /* dump the buffer's contents */
-
- printf("\n\n");
- while((rlen = prb_read_rectype(&sample,&rectype)) != 0) {
- switch(rectype) {
- case 0: /* deal with string records */
- prb_read_data(&sample,workbuf);
- *(workbuf+rlen) = 0; /* add a string terminator */
- printf("rectype 0: %s\n",workbuf);
- break;
- case 1: /* deal with integer records */
- prb_read_data(&sample,&y);
- printf("rectype 1: %04X\n",y);
- break;
- default:
- printf("\nError - undefined rectype: %d\n",rectype);
- }
- }
- }
-